home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / move.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  10KB  |  351 lines

  1. /*
  2.  * static char *rcsid_move_c =
  3.  *    "$Id: move.c,v 1.13 1994/12/30 07:56:43 master Exp $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27. */
  28.  
  29. #include <global.h>
  30. #ifndef __CEXTRACT__
  31. #include <sproto.h>
  32. #endif
  33.  
  34. int move_ob(object *op,int dir) {
  35.   object *tmp=NULL;
  36.   object *tmp_ob=NULL;
  37.  
  38.   if(op==NULL) {
  39.     LOG(llevError,"Trying to move NULL.\n");
  40.     return 0;
  41.   }
  42.  
  43.   if (op->type==PLAYER)
  44.     op->contr->freeze_look=1;
  45.  
  46.   /* If this is a multipart object and we are dealing with the
  47.    * head, remove the object.  It needs to be removed, otherwise
  48.    * it may block itself from moving to that space (You can't
  49.    * move onto the tail section of the monster, and this is true
  50.    * even if it is your own tail
  51.    */
  52.   if(op->more!=NULL && op->head==NULL)
  53.     remove_ob(op);
  54.  
  55. /* Vick's (vick@bern.docs.uu.se) @921108 -> If a monster can apply
  56.  * an earthwall (or a door), then walking into it means tearing it down.
  57.  * Note taht a player should never have will_apply set, so thus
  58.  * the following two sections will not be used for players -
  59.  * the routines in move_player_attack will be used instead.
  60.  */
  61.  
  62.   if (op->will_apply&4 &&
  63.       !out_of_map(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir])) {
  64.  
  65.     tmp_ob=get_map_ob(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir]);
  66.  
  67.     if (tmp_ob!=NULL) {
  68.       while(tmp_ob->above != NULL)
  69.         tmp_ob=tmp_ob->above;
  70.  
  71.       if (tmp_ob->type == EARTHWALL)
  72.     hit_player(tmp_ob,5,op,AT_PHYSICAL); /* Tear down the earthwall */
  73.     }
  74.   }
  75.   if (op->will_apply&8 &&
  76.       !out_of_map(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir])) {
  77.  
  78.     tmp_ob=get_map_ob(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir]);
  79.     if (tmp_ob!=NULL) {
  80.       while(tmp_ob->above != NULL)
  81.         tmp_ob=tmp_ob->above;
  82.       if (tmp_ob->type == DOOR)
  83.         hit_player(tmp_ob,9999,op,AT_PHYSICAL); /* Break open the door. */
  84.     }
  85.   }
  86.  
  87.   /* Eneq(@csd.uu.se): Use blocked_two when selecting direction.
  88.    * The following if statement works like this:  If WIZPASS is
  89.    * set, then the player is prevented from moving to that
  90.    * space if it is out_of_map.  If non WIZPASS, then
  91.    * blocked_two is called instead.
  92.    * This code section is for cases when an object CAN NOT move into
  93.    * that space.
  94.    */
  95.  
  96.   if(QUERY_FLAG(op,FLAG_WIZPASS)?out_of_map(op->map,op->x+freearr_x[dir],
  97.     op->y+freearr_y[dir]):
  98.     blocked_two(op,op->x+freearr_x[dir],op->y+freearr_y[dir])) {
  99.  
  100.     /* Re insert object if we removed it above */
  101.     if(op->more!=NULL && op->head==NULL)
  102.       insert_ob_in_map(op,op->map);
  103.     if (op->type==PLAYER)
  104.       op->contr->freeze_look=0;
  105.     return 0;
  106.   }
  107.  
  108.   /* Following deals with situation when the object can move
  109.    * into the desired space.
  110.    */
  111.  
  112.   /* this is a single parted object that needs to be removed. */
  113.   if(op->more==NULL && op->head==NULL)
  114.     remove_ob(op);
  115.  
  116.   /* This handles multipart objects.  It uses recursion to
  117.    * make sure all the parts will fit in the new space.
  118.    * First, tmp is set the the next segment (op->more), with
  119.    * that being set to null.  Then call move_ob to see if
  120.    * that segment (and also all segments beyond it) can
  121.    * move to taht space.  IF not (!move_ob), then reset op->more.
  122.    * If it is the head segment, insert back to map.  Clear freeze_look
  123.    * if player, and return failed result.
  124.    */
  125.   if(op->more!=NULL) {
  126.     tmp=op->more,op->more=NULL;
  127.     if(!move_ob(tmp,dir)) {
  128.       op->more=tmp;
  129.       if(op->head==NULL)
  130.         insert_ob_in_map(op,op->map);
  131.       if (op->type==PLAYER)
  132.     op->contr->freeze_look=0;
  133.       return 0;
  134.     }
  135.     else op->more=tmp;
  136.   }
  137.   op->x+=freearr_x[dir],op->y+=freearr_y[dir];  /* Move this object */
  138.  
  139.   if (op->type == PLAYER && op->contr->eric_server > 0) {
  140.     esrv_map_scroll(op->contr->eric_server,
  141.                   freearr_x[dir],freearr_y[dir]);
  142.   }
  143.  
  144.   /* If head of object (or single part object), reinsert into map. */
  145.   if(op->head==NULL)
  146.     insert_ob_in_map(op,op->map);
  147.  
  148.   if (op->type==PLAYER) {
  149.     op->contr->freeze_look=0;
  150.     draw_look(op);
  151.   }
  152.   return 1;
  153. }
  154.  
  155.  
  156. /*
  157.  * transfer_ob(): Move an object (even linked objects) to another spot
  158.  * on the same map.
  159.  */
  160.  
  161. void transfer_ob(object *op,int x,int y) {
  162.   int i=find_first_free_spot(op->arch,op->map,x,y);
  163.   object *tmp;
  164.   if(op->head!=NULL)
  165.     op=op->head;
  166.   remove_ob(op);
  167.   for(tmp=op;tmp!=NULL;tmp=tmp->more)
  168.     tmp->x=x+freearr_x[i]+(tmp->arch==NULL?0:tmp->arch->clone.x),
  169.     tmp->y=y+freearr_y[i]+(tmp->arch==NULL?0:tmp->arch->clone.y);
  170.   insert_ob_in_map(op,op->map);
  171. }
  172.  
  173. void teleport(object *teleporter,unsigned char tele_type) {
  174.   object *altern[120]; /* Better use c/malloc here in the future */
  175.   int i,j,k,nrofalt=0;
  176.   object *other_teleporter,*teleported=teleporter->above,*tmp;
  177.  
  178.   if(teleported==NULL) return;
  179.   if(teleported->head!=NULL)
  180.     teleported=teleported->head;
  181.   for(i= -5;i<6;i++)
  182.     for(j= -5;j<6;j++) {
  183.       if(i==0&&j==0)
  184.     continue;
  185.       if(out_of_map(teleporter->map,teleporter->x+i,teleporter->y+j))
  186.         continue;
  187.       other_teleporter=get_map_ob(teleporter->map,
  188.                                   teleporter->x+i,teleporter->y+j);
  189.       if(other_teleporter==NULL
  190.      || (other_teleporter->type!=tele_type
  191.          && (other_teleporter->above==NULL
  192.          || other_teleporter->above->type!=tele_type)))
  193.         continue;
  194.       altern[nrofalt++]=other_teleporter;
  195.     }
  196.   if(!nrofalt) {
  197.     LOG(llevError,"No alternative teleporters around!\n");
  198.     return;
  199.   }
  200.   other_teleporter=altern[RANDOM()%nrofalt];
  201.   if(!(k=find_free_spot(teleported->arch,other_teleporter->map,
  202.                         other_teleporter->x,other_teleporter->y,1,9)))
  203.     return;
  204.   remove_ob(teleported);
  205.   for(tmp=teleported;tmp!=NULL;tmp=tmp->more)
  206.     tmp->x=other_teleporter->x+freearr_x[k]+
  207.            (tmp->arch==NULL?0:tmp->arch->clone.x),
  208.     tmp->y=other_teleporter->y+freearr_y[k]+
  209.            (tmp->arch==NULL?0:tmp->arch->clone.y);
  210.   insert_ob_in_map(teleported,other_teleporter->map);
  211. }
  212.  
  213. void recursive_roll(object *op,int dir,object *pusher) {
  214.   if(!roll_ob(op,dir,pusher)) {
  215.     new_draw_info_format(NDI_UNIQUE, 0, pusher,
  216.     "You fail to push the %s.",query_name(op));
  217.     return;
  218.   }
  219.   (void) move_ob(pusher,dir);
  220.   new_draw_info_format(NDI_BLACK, 0, pusher,
  221.     "You roll the %s.",query_name(op));
  222.   return;
  223. }
  224.  
  225. /*
  226.  * This is a new version of blocked, this one handles objects
  227.  * that can be passed through by monsters with the CAN_PASS_THRU defined.
  228.  *
  229.  * very new version handles also multipart objects
  230.  */
  231.  
  232. int try_fit (object *op, int x, int y) 
  233. {
  234.     object *tmp, *more;
  235.     int tx, ty;
  236.     if (op->head) 
  237.     op = op->head;
  238.  
  239.     for (more = op; more ; more = more->more) {
  240.     tx = x + more->x - op->x;
  241.     ty = y + more->y - op->y;
  242.     if (out_of_map(op->map,tx,ty))
  243.         return 1;
  244.  
  245.     for (tmp = get_map_ob (more->map, tx, ty); tmp; tmp=tmp->above) {
  246.         if (tmp->head == op || tmp == op)
  247.         continue;
  248.  
  249.         if ((QUERY_FLAG(tmp,FLAG_ALIVE) && tmp->type!=DOOR))
  250.         return 1;
  251.  
  252.         if (QUERY_FLAG(tmp,FLAG_NO_PASS) && 
  253.         (!QUERY_FLAG(tmp,FLAG_PASS_THRU) ||
  254.          !QUERY_FLAG(more,FLAG_CAN_PASS_THRU)))
  255.         return 1;
  256.     }
  257.     }
  258.     return 0;
  259. }
  260.  
  261. /*
  262.  * this is not perfect yet. 
  263.  * it does not roll objects behind multipart objects properly.
  264.  */
  265.  
  266. int roll_ob(object *op,int dir, object *pusher) {
  267.     object *tmp;
  268.     int x, y;
  269.     if (op->head) 
  270.     op = op->head;
  271.     x=op->x+freearr_x[dir];
  272.     y=op->y+freearr_y[dir];
  273.     if(!QUERY_FLAG(op,FLAG_CAN_ROLL) || 
  274.        (op->weight&&RANDOM() % (op->weight/50000) > pusher->stats.Str))
  275.     return 0;
  276.  
  277.     if(out_of_map(op->map,x,y))
  278.     return 0;
  279.  
  280.     for(tmp=get_map_ob(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir]);
  281.     tmp!=NULL;tmp=tmp->above) {
  282.     if (tmp->head == op)
  283.         continue;
  284.     if(QUERY_FLAG(tmp,FLAG_ALIVE))
  285.         return 0;
  286.     if (QUERY_FLAG(tmp,FLAG_NO_PASS) && !roll_ob(tmp,dir,pusher))
  287.         return 0;
  288.     }
  289.     if (try_fit (op, x, y))
  290.     return 0;
  291.  
  292.     remove_ob(op);
  293.     for(tmp=op; tmp!=NULL; tmp=tmp->more)
  294.     tmp->x+=freearr_x[dir],tmp->y+=freearr_y[dir];
  295.     insert_ob_in_map(op,op->map);
  296.     return 1;
  297. }
  298.  
  299. int push_ob(object *who, int dir, object *pusher) {
  300.   int str1, str2;
  301.   object *owner;
  302.  
  303.   if (who->head != NULL)
  304.     who = who->head;
  305.   owner = get_owner(who);
  306.   if (who->more == NULL && owner == pusher) {
  307.     int temp;
  308.     remove_ob(who);
  309.     remove_ob(pusher);
  310.     temp = pusher->x;
  311.     pusher->x = who->x;
  312.     who->x = temp;
  313.     temp = pusher->y;
  314.     pusher->y = who->y;
  315.     who->y = temp;
  316.     insert_ob_in_map (who,who->map);
  317.     insert_ob_in_map (pusher,pusher->map);
  318.     return 0;
  319.   }
  320.   if(QUERY_FLAG(who,FLAG_UNAGGRESSIVE) && owner != pusher)
  321.     who->enemy = pusher;
  322.   str1 = (who->stats.Str>0?who->stats.Str:who->level);
  323.   str2 = (pusher->stats.Str>0?pusher->stats.Str:pusher->level);
  324.   if(QUERY_FLAG(who,FLAG_WIZ) || RANDOM()%(str1/2+1) + str1 >= RANDOM()%(str2/2+1) + str2 ||
  325.      !move_ob(who,dir))
  326.   {
  327.     if (who ->type == PLAYER) {
  328.       new_draw_info_format(NDI_UNIQUE, 0, who,
  329.     "%s tried to push you.",pusher->name);
  330.     }
  331.     if (QUERY_FLAG(who, FLAG_MONSTER)) {
  332.       new_draw_info_format(NDI_UNIQUE, 0, pusher,
  333.     "Your pushing annoys %s.",who->name);
  334.     }
  335.     return 0;
  336.   }
  337.   if (who->type == PLAYER) {
  338.     new_draw_info_format(NDI_UNIQUE, 0, who,
  339.     "%s pushed you.",pusher->name);
  340.   }
  341.   if (QUERY_FLAG(who, FLAG_MONSTER)) {
  342.     if(owner == pusher)
  343.       new_draw_info_format(NDI_UNIQUE, 0,pusher,
  344.     "%s doesn't seem pleased with your action.",who->name);
  345.     else
  346.       new_draw_info_format(NDI_UNIQUE, 0,pusher,
  347.     "%s is definitely annoyed at your pushing.",who->name);
  348.   }
  349.   return 1;
  350. }
  351.